package org.jtrace.geometry;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.jtrace.Hit;
import org.jtrace.Jay;
import org.jtrace.Material;
import org.jtrace.Materials;
import org.jtrace.NotHit;
import org.jtrace.examples.io.SimplePLYExample;
import org.jtrace.io.PlyReader;
import org.jtrace.primitives.ColorRGB;
import org.jtrace.primitives.Point3D;

public class Mesh extends GeometricObject {
	protected final Set<Triangle> triangles = new LinkedHashSet<Triangle>();
	protected Point3D center;
	protected Point3D min;
	protected Point3D max;
	
	public Mesh(Material material) {
		super(material);
	}
	
	public Mesh(String plyPath, Material material) {
		super(material);
		
		center = new Point3D(0, 0, 0);
		min = new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
		max = new Point3D(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
		
		loadMesh(plyPath);
	}
	
	private void loadMesh(String plyPath) {
		InputStream is = SimplePLYExample.class.getResourceAsStream(plyPath);
		
		try {
			List<Triangle> triangles = PlyReader.read(is, Materials.metallic(ColorRGB.RED));			
			
			for(Triangle triangle : triangles) {
				this.triangles.add(triangle);
				
				updateBounds(triangle.getV1());
				updateBounds(triangle.getV2());
				updateBounds(triangle.getV3());
			}
			
			updateCenter();
			
			//this.triangles.addAll(triangles);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Hit hit(Jay jay) {
		Hit hit = new NotHit();
		
		for (Triangle triangle : triangles) {
			Hit newHit = triangle.hit(jay);
			
			if ((newHit.isHit() && !hit.isHit()) || (newHit.isHit() && hit.isHit() && newHit.getT() < hit.getT()))
				hit = newHit;
		}
		
		return hit;
	}
	
	protected void updateBounds(Point3D vertex) {
		if (vertex.getX() < min.getX()) min.setX(vertex.getX());
		if (vertex.getY() < min.getY()) min.setY(vertex.getY());
		if (vertex.getZ() < min.getZ()) min.setZ(vertex.getZ());
		if (vertex.getX() > max.getX()) max.setX(vertex.getX());
		if (vertex.getY() > max.getY()) max.setY(vertex.getY());
		if (vertex.getZ() > max.getZ()) max.setZ(vertex.getZ());
	}
	
	protected void updateCenter() {
		Point3D distance = max.subtract(min);
		distance.multiply(0.5); // divide por 2
		center = min.add(distance);
	}


	public Set<Triangle> getTriangles() {
		return triangles;
	}

	@Override
	public Point3D getCenter() {
		return center;
	}
	
	@Override
	public double getHeight() {
		return max.getZ() - min.getZ();
	}
}
